//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package impl

import (
	"context"

	"atomgit.com/openlinksaas/mongo-proxy/gen_code"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type CollectionApiImpl struct{}

func (s *CollectionApiImpl) CollectionDeletePost(ctx context.Context, req gen_code.CollectionDeletePostRequest) (gen_code.ImplResponse, error) {
	if req.Token != token {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: "wrong token",
			},
		}, nil
	}

	query := bson.M{}
	err := bson.UnmarshalExtJSON([]byte(req.Query), false, &query)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}
	if query["_id"] == nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: "wrong docId",
			},
		}, nil
	}

	infoItem, ok := clientMap.Load(req.Id)
	if !ok {
		return gen_code.ImplResponse{
			Code: 200,
			Body: req.Query,
		}, nil
	}
	info := infoItem.(*ClientInfo)
	client := info.client.(*mongo.Client)
	coll := client.Database(req.Database).Collection(req.Collection)
	_, err = coll.DeleteOne(ctx, query)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}
	return gen_code.ImplResponse{
		Code: 200,
		Body: req.Query,
	}, nil
}

func (s *CollectionApiImpl) CollectionFindPost(ctx context.Context, req gen_code.CollectionFindPostRequest) (gen_code.ImplResponse, error) {
	if req.Token != token {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: "wrong token",
			},
		}, nil
	}

	query := bson.M{}
	err := bson.UnmarshalExtJSON([]byte(req.Query), false, &query)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}

	infoItem, ok := clientMap.Load(req.Id)
	if !ok {
		return gen_code.ImplResponse{
			Code: 200,
			Body: req.Id,
		}, nil
	}
	info := infoItem.(*ClientInfo)
	client := info.client.(*mongo.Client)
	coll := client.Database(req.Database).Collection(req.Collection)

	count, err := coll.CountDocuments(ctx, query)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}

	docList := []bson.M{}
	cursor, err := coll.Find(ctx, query, options.Find().SetSkip(int64(req.Offset)).SetLimit(int64(req.Limit)))
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}
	err = cursor.All(ctx, &docList)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}
	retList := []string{}
	for _, doc := range docList {
		data, err := bson.MarshalExtJSON(doc, false, false)
		if err != nil {
			return gen_code.ImplResponse{
				Code: 500,
				Body: gen_code.ErrInfo{
					ErrMsg: err.Error(),
				},
			}, nil
		}
		retList = append(retList, string(data))
	}
	return gen_code.ImplResponse{
		Code: 200,
		Body: gen_code.CollectionFindPost200Response{
			Count: int32(count),
			Docs:  retList,
		},
	}, nil
}

func (s *CollectionApiImpl) CollectionListPost(ctx context.Context, req gen_code.CollectionListPostRequest) (gen_code.ImplResponse, error) {
	if req.Token != token {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: "wrong token",
			},
		}, nil
	}

	infoItem, ok := clientMap.Load(req.Id)
	if !ok {
		return gen_code.ImplResponse{
			Code: 200,
			Body: req.Id,
		}, nil
	}
	info := infoItem.(*ClientInfo)
	client := info.client.(*mongo.Client)

	names, err := client.Database(req.Database).ListCollectionNames(ctx, bson.M{})
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}
	return gen_code.ImplResponse{
		Code: 200,
		Body: names,
	}, nil
}

func (s *CollectionApiImpl) CollectionUpdatePost(ctx context.Context, req gen_code.CollectionInsertPostRequest) (gen_code.ImplResponse, error) {
	if req.Token != token {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: "wrong token",
			},
		}, nil
	}

	doc := bson.M{}
	err := bson.UnmarshalExtJSON([]byte(req.Doc), false, &doc)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}
	if doc["_id"] == nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: "no _id in doc",
			},
		}, nil
	}

	infoItem, ok := clientMap.Load(req.Id)
	if !ok {
		return gen_code.ImplResponse{
			Code: 200,
			Body: req.Id,
		}, nil
	}
	info := infoItem.(*ClientInfo)
	client := info.client.(*mongo.Client)

	coll := client.Database(req.Database).Collection(req.Collection)

	_, err = coll.UpdateOne(ctx, bson.M{"_id": doc["_id"]}, bson.M{"$set": doc})
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}
	idData, err := bson.MarshalExtJSON(bson.M{"_id": doc["_id"]}, false, false)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}
	return gen_code.ImplResponse{
		Code: 200,
		Body: string(idData),
	}, nil
}

func (s *CollectionApiImpl) CollectionInsertPost(ctx context.Context, req gen_code.CollectionInsertPostRequest) (gen_code.ImplResponse, error) {
	if req.Token != token {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: "wrong token",
			},
		}, nil
	}

	doc := bson.M{}
	err := bson.UnmarshalExtJSON([]byte(req.Doc), false, &doc)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}

	infoItem, ok := clientMap.Load(req.Id)
	if !ok {
		return gen_code.ImplResponse{
			Code: 200,
			Body: req.Id,
		}, nil
	}
	info := infoItem.(*ClientInfo)
	client := info.client.(*mongo.Client)

	coll := client.Database(req.Database).Collection(req.Collection)

	result, err := coll.InsertOne(ctx, doc)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}
	idData, err := bson.MarshalExtJSON(bson.M{"_id": result.InsertedID}, false, false)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}
	return gen_code.ImplResponse{
		Code: 200,
		Body: string(idData),
	}, nil
}

func (s *CollectionApiImpl) ViewListPost(ctx context.Context, req gen_code.ViewListPostRequest) (gen_code.ImplResponse, error) {
	if req.Token != token {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: "wrong token",
			},
		}, nil
	}

	infoItem, ok := clientMap.Load(req.Id)
	if !ok {
		return gen_code.ImplResponse{
			Code: 200,
			Body: req.Id,
		}, nil
	}
	info := infoItem.(*ClientInfo)
	client := info.client.(*mongo.Client)

	coll := client.Database(req.Database).Collection(req.Collection)

	cursor, err := coll.Indexes().List(ctx)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}

	indexList := []bson.M{}
	err = cursor.All(ctx, &indexList)
	if err != nil {
		return gen_code.ImplResponse{
			Code: 500,
			Body: gen_code.ErrInfo{
				ErrMsg: err.Error(),
			},
		}, nil
	}

	resultList := []string{}
	for _, index := range indexList {
		data, err := bson.MarshalExtJSON(index, false, false)
		if err != nil {
			return gen_code.ImplResponse{
				Code: 500,
				Body: gen_code.ErrInfo{
					ErrMsg: err.Error(),
				},
			}, nil
		}
		resultList = append(resultList, string(data))
	}

	return gen_code.ImplResponse{
		Code: 200,
		Body: resultList,
	}, nil
}
